package com.rpa.server.servicerpaserver.crawler.operate;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.beust.ah.A;
import com.rpa.secure.servicerpasecure.common.constant.MessageConstant;
import com.rpa.secure.servicerpasecure.common.constant.ParameterConstant;
import com.rpa.secure.servicerpasecure.common.constant.UrlConstant;
import com.rpa.secure.servicerpasecure.common.exception.TaskException;
import com.rpa.secure.servicerpasecure.common.util.CurrentTeacherInfoUtil;
import com.rpa.server.servicerpaserver.crawler.entity.Clazz;
import com.rpa.server.servicerpaserver.crawler.entity.Score;
import com.rpa.server.servicerpaserver.crawler.entity.User;
import com.rpa.server.servicerpaserver.crawler.service.ClazzService;
import com.rpa.server.servicerpaserver.crawler.service.ScoreService;
import com.rpa.server.servicerpaserver.crawler.service.UserService;
import com.rpa.server.servicerpaserver.util.CookieSerialize;
import com.rpa.server.servicerpaserver.util.WebDriverUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @className: ClazzOperate
 * @author: lzt
 * @date: 2025/1/24 17:03
 * @Version: 1.0
 * @description:
 */
@Component
@Slf4j
public class ClazzOperate {
    @Autowired
    private CookieSerialize cookieSerialize;
    @Autowired
    private UserService uerService;
    @Autowired
    private ClazzService clazzService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ScoreService scoreService;

    @Async("clazzTaskExecutor")
    public CompletableFuture<Boolean> getClass(String accountId,String courseId) {
        log.info("获取班级名单信息");

        // 校验用户是否存在
        User user = uerService.getById(accountId);
        if (user == null) {
            throw new TaskException(MessageConstant.NO_USER);
        }

        // 调用异步方法获取班级id
        CompletableFuture<List<Map>> classIdsFuture = this.getClassIds(accountId, courseId);

        // 异步任务处理，等待结果
        CompletableFuture<Boolean> exceptionally = classIdsFuture.thenApply(classIds -> {
            if (CollUtil.isEmpty(classIds)) {
                log.error(MessageConstant.NO_CLASS);
            }
            classIds.forEach(classId -> {
                // 你可以在这里处理每个classId
                List<Clazz> classNameList = this.getClassNameList(classId, accountId);
                if (CollUtil.isEmpty(classNameList)) {
                    log.error(MapUtil.getStr(classId, "className") + MapUtil.getStr(classId, "id") + MessageConstant.STUDENT_NULL);
                }
                handleSingleClass(classId, courseId, accountId, classNameList);
            });
            return true;
        }).exceptionally(ex -> {
            log.error("处理班级名单信息时发生错误", ex);
            return false;
        });

        return exceptionally;
    }
    //获取课程班级id和总数
    @Async("clazzIdTaskExecutor")
    public CompletableFuture<List<Map>> getClassIds(String accountId,String courseId) {
        log.info("获取课程班级id和总数");
        User user = uerService.getById(accountId);
        if (user == null) {
            throw new TaskException(MessageConstant.NO_USER);
        }

        ChromeOptions options = new ChromeOptions();
        WebDriverUtil.setupWebDriver(options);
        ChromeDriver chromeDriver = null;
        List<Map> classIds = new ArrayList<>();

        try {
            chromeDriver = new ChromeDriver(options);
            cookieSerialize.goFZF(accountId+"WORK", ParameterConstant.ROUTE_WIDGET, chromeDriver);
            chromeDriver.get(StrUtil.format(UrlConstant.MANAGE_PAGE_COUNT, cookieSerialize.getCookieValue(accountId, ParameterConstant.FID), courseId));
            cookieSerialize.delAfterSaveCookies(accountId+"WORK", chromeDriver.manage().getCookies());
            classIds = WebDriverUtil.getWebDriverDate(chromeDriver);
        } catch (Exception e) {
            log.error("获取班级名单信息失败", e);
            throw new TaskException(MessageConstant.GET_CLASS_ERROR);
        } finally {
            WebDriverUtil.closeWebDriver(chromeDriver);
        }
        // 使用 CompletableFuture 来返回异步结果
        return CompletableFuture.completedFuture(classIds);
    }

    @Async("clazzNameListTaskExecutor")
    public List<Clazz> getClassNameList(Map map, String accountId) {
        log.info("获取班级名单信息");
        if (MapUtil.isEmpty(map)) {
            throw new TaskException(MessageConstant.PARAMETER_ERROR);
        }
        ChromeOptions options = new ChromeOptions();
        WebDriverUtil.setupWebDriver(options);
        ChromeDriver chromeDriver = null;
        List<Clazz> allClazz = new ArrayList<>();
        try {
            chromeDriver = new ChromeDriver(options);
            cookieSerialize.goFZF1(accountId, chromeDriver);
            Integer anInt = MapUtil.getInt(map, ParameterConstant.STUDENTCOUNT, 0);
            String str = MapUtil.getStr(map, ParameterConstant.COURSEID, "");
            String classId = MapUtil.getStr(map, ParameterConstant.ID, "");
            Integer pageNum = 1;
            if (anInt > 0) {
                // 页面跳转到计数管理页面
                chromeDriver.get(StrUtil.format(UrlConstant.COUNT_MANAGE_PAGE, str, classId, String.valueOf(pageNum)));
                List<Clazz> classNameListByElement = this.getClassNameListByElement(chromeDriver, str,classId,accountId);
                allClazz.addAll(classNameListByElement);
                while (classNameListByElement.size() > 0 && allClazz.size() < anInt && pageNum <= anInt) {
                    pageNum++;
                    chromeDriver.get(StrUtil.format(UrlConstant.COUNT_MANAGE_PAGE, str, classId, String.valueOf(pageNum)));
                    classNameListByElement = this.getClassNameListByElement(chromeDriver, str,classId,accountId);
                    allClazz.addAll(classNameListByElement);
                }
                if (pageNum > anInt) {
                    log.error("获取班级名单信息失败,数目异常");
                   // throw new TaskException(MessageConstant.GET_CLASS_ERROR);
                    return allClazz;

                } else {
                    return allClazz;
                }
            }else {
                return allClazz;
            }
        } catch (Exception e) {
            log.error("获取班级名单信息失败", e);
            return allClazz;
           // throw new TaskException(MessageConstant.GET_CLASS_ERROR);
        } finally {
            WebDriverUtil.closeWebDriver(chromeDriver);
        }
    }

    //从界面中获取数据
    public List<Clazz> getClassNameListByElement(ChromeDriver chromeDriver, String courseId,String classId,String accountId) {
        List<Clazz> clazzList = new ArrayList<>();
        WebElement divElement = chromeDriver.findElement(By.xpath("//*[@id=\"studentTable\"]/tbody"));
        List<WebElement> trElements = divElement.findElements(By.tagName("tr"));
        for (WebElement trElement : trElements) {
            WebElement studentIdElement = trElement.findElement(By.xpath("./td[2]"));
            String studentId = studentIdElement.getText();

            WebElement studentNameElement = trElement.findElement(By.xpath(".//span[@class='photo-txt']"));
            String studentName = studentNameElement.getText();

            WebElement studentCodeElement = trElement.findElement(By.xpath(".//div[@class='stu-txt']"));
            String studentCode = studentCodeElement.getText();

            WebElement collegeElement = trElement.findElement(By.xpath("./td[5]"));
            String college = collegeElement.getText();

            WebElement majorElement = trElement.findElement(By.xpath("./td[6]"));
            String major = majorElement.getText();

            WebElement classNameElement = trElement.findElement(By.xpath("./td[7]"));
            String className = classNameElement.getText();

            Clazz clazz = Clazz.builder()
                    .studentNumber(studentCode)
                    .personId(studentId)
                    .userName(studentName)
                    .college(college)
                    .major(major)
                    .faculty(className)
                    .accountId(accountId)
                    .courseId(courseId)
                    .clazzId(classId)
                    .build();
            clazzList.add(clazz);
        }
        return clazzList;
    }
    public Boolean deleteClass(String classId, String courseId,String accountId) {
        LambdaUpdateWrapper<Clazz> lambdaUpdateWrapper  = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Clazz::getClazzId,classId)
                .eq(Clazz::getAccountId,accountId)
                .eq(Clazz::getCourseId,courseId)
                ;
        return clazzService.remove(lambdaUpdateWrapper);
    }


    /**
     * 处理单个班级信息
     * @param classId 班级id
     * @param courseId 课程id
     * @param accountId 用户id
     */
    @Transactional
    public void handleSingleClass(Map classId, String courseId, String accountId,List<Clazz>classNameList) {
        if (CollUtil.isEmpty(classNameList)) {
           // throw new TaskException(MessageConstant.STUDENT_NULL);
            log.error("该班级为空");
            return;
        }
        List<Score> scoreActive = batchUpdateOrInsertScores(classNameList);
        // 批量更新班级信息
        RLock lock = redissonClient.getLock(classId.get("id").toString());
        try{
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                this.deleteClass(classId.get("id").toString(), courseId, accountId);
                clazzService.saveBatch(classNameList);
                if (CollUtil.isNotEmpty(scoreActive)){
                    scoreService.saveBatch(scoreActive);
                }
            }else{
                log.error("获取锁失败");
            }
        }catch (InterruptedException e) {
            log.error("获取锁失败", e);
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    public List<Score> getScoreActive(List<Clazz>classNameList){
        return classNameList.stream().map(clazz -> {
            return Score.builder()
                   .accountId(clazz.getAccountId())
                   .courseId(clazz.getCourseId())
                   .clazzId(clazz.getClazzId())
                   .scoreName("")
                    .userName(clazz.getUserName())
                   .scoreNumber((double) 100)
                   .scoreType(3)
                   .isStart(0)
                   .build();
        }).collect(Collectors.toList());
    }
    public List<Score> batchUpdateOrInsertScores(List<Clazz> classNameList) {
        // 获取需要添加的 Score 记录
        List<Score> scoreActive = getScoreActive(classNameList);

        // 查询数据库中已有的 Score 记录
        List<Score> existingScores = scoreService.list(new QueryWrapper<Score>()
                        .eq("is_start", 0)
                        .eq("score_type", 3)
                .in("account_id", scoreActive.stream().map(Score::getAccountId).collect(Collectors.toList()))
                .in("course_id", scoreActive.stream().map(Score::getCourseId).collect(Collectors.toList()))
                .in("clazz_id", scoreActive.stream().map(Score::getClazzId).collect(Collectors.toList()))
                .in("user_name", scoreActive.stream().map(Score::getUserName).collect(Collectors.toList())));

        // 将已有的 Score 记录转换为 Map 以便快速查找
        Map<String, Score> existingScoresMap = existingScores.stream()
                .collect(Collectors.toMap(
                        score -> buildCompositeKey(score.getAccountId(), score.getCourseId(), score.getClazzId(), score.getUserName()),
                        score -> score
                ));

        // 过滤需要添加的 Score 记录
        List<Score> scoresToInsert = scoreActive.stream()
                .filter(score -> !existingScoresMap.containsKey(buildCompositeKey(score.getAccountId(), score.getCourseId(), score.getClazzId(), score.getUserName())))
                .collect(Collectors.toList());
        return scoresToInsert;
    }
    private String buildCompositeKey(String accountId, String courseId, String clazzId, String userName) {
        return accountId + "_" + courseId + "_" + clazzId + "_" + userName;
    }

}
